#include "MainRenderState.h"
#include "Screen.h"
#include "ReportError.h"
#include "EventPoller.h"
#include "Scene.h"
#include "Game.h"
#include "Timer.h"
#include <SDL_opengl.h>
#include <cassert>
#include <sstream>
#include "IntroState.h"


static void TW_CALL Quit(void *clientData)
{  
    TheGame::Instance()->Quit();
}
static void TW_CALL Reset(void *clientData)
{  
    TheMainRenderState::Instance()->ResetCamera();
}
static void TW_CALL Reverse(void *clientData)
{  
    TheMainRenderState::Instance()->ChangeDirection();
}
/* Construction */
MainRenderState::MainRenderState() :    
m_bar(NULL),
m_screenX(0),
m_screenY(0),
m_frameDisplay(0.0f),
m_work(true),
m_workCount(0),
m_FrameTimeDisplay(0.0)
{
}

/* Main Update called once per frame */
void MainRenderState::Update()
{
#ifdef DEBUGGING
    CheckErrors();  
#endif


}

/* Main Draw called once per frame */
void MainRenderState::Draw()
{
    //Clear the active buffers
    glClear(GL_COLOR_BUFFER_BIT |GL_DEPTH_BUFFER_BIT | GL_ACCUM_BUFFER_BIT);
    if(m_work)
        m_workCount = 0;
    if(!m_work && m_workCount == 0)
    {
        m_workCount = 1;
        m_scene.RenderMultipleThreaded();
    }
    if(m_work && m_workCount == 0)
    {
        m_frameDisplay = TheTimer::Instance()->GetFrameRate();
        m_FrameTimeDisplay = TheTimer::Instance()->GetFrameTimeHR();
        m_scene.RenderMultipleThreaded();
        m_scene.ClearBuffers();
    }
    else
    {
        m_scene.GLRenderPixels();
    }

    TwDraw();
}

/* Called by TheGame once on first Use */
void MainRenderState::Initialise()
{  
#ifdef DEBUGGING
    std::cout << "{MainRenderState Singleton} Initialising()..." << std::endl;
#endif
    
    if(m_bar == NULL)
    {
        m_bar = TwNewBar("Back");
    }
    else
    {
        m_bar = TwGetBarByName("Back");
        TwRemoveAllVars(m_bar);
    }
    if(m_bar == NULL)
        assert(0);
    SetUpUI();

    GameState::SetVsync(0);
    //build the scene
    
    m_scene.Build(m_data);
    
    //Set the flag
    m_initialised = true;
    TheEventPoller::Instance()->AddHandler(this);
#ifdef DEBUGGING
    std::cout << "{MainRenderState Singleton} Initialised Succesfully : " << std::endl;
#endif
}

/* Called by TheGame when managing game states or exiting */
void MainRenderState::CleanUp()
{ 
#ifdef DEBUGGING
    std::cout << "{MainRenderState Singleton} Calling CleanUp()..." << std::endl;
#endif

    TheEventPoller::Instance()->RemoveHandler(this);
    TwDefine("Back visible=false");
    m_scene.CleanUp();

#ifdef DEBUGGING
    std::cout << "{MainRenderState Singleton} CleanUp sucesfull" << std::endl;
#endif
}

/* Called by TheGame when re-using this state ( Initialize has all ready been called) */
void MainRenderState::OnResume()
{
#ifdef DEBUGGING
    std::cout << "{MainRenderState Singleton} Resuming..." << std::endl;
#endif

    m_work = true; m_workCount = 0;
    TheEventPoller::Instance()->AddHandler(this);
    m_bar = TwGetBarByName("Back");
    TwRemoveAllVars(m_bar);
    if(m_bar == 0)
        assert(0);
    TwDefine("Back visible=true");
    SetUpUI();
    m_scene.Build(m_data);
#ifdef DEBUGGING
    std::cout << "{MainRenderState Singleton} Resumed Succesfully..." << std::endl;
#endif
}

/* Managing input*/
void MainRenderState::OnKeyBoardDownEvent(const SDL_KeyboardEvent& Event)
{    
    switch(Event.keysym.sym)
    {
    case SDLK_c :
        {
            system("cls");
            break;
        }
    }
}

static void TW_CALL Back(void *clientData)
{  
    TheGame::Instance()->RequestChange(TheIntroState::Instance());
}

void MainRenderState::SetUpUI()
{
    TestTw(TwDefine("Back color='0 0 0' alpha=0 "));    
    TestTw(TwDefine("Back position = '0 0'"));
    TestTw(TwDefine("Back iconifiable=false"));
    TestTw(TwDefine("Back movable=false"));
    TestTw(TwDefine("Back resizable=false"));
    TestTw(TwDefine("Back fontresizable=false"));

    //SIZE
    std::string size = "Back size = '";
    std::stringstream sizeSS;
    sizeSS << 212 << " " << 300 <<"' ";
    size +=sizeSS.str();
    TestTw(TwDefine(size.c_str()));
    //work
    TwAddVarRW(m_bar, "Work", TW_TYPE_BOOLCPP, &m_work, "label = 'Update'");
    TestTw(TwAddSeparator(m_bar,NULL,NULL));
    //back
    TwAddButton(m_bar, "Back", (TwButtonCallback)&Back, NULL, NULL );
    TestTw(TwAddSeparator(m_bar,NULL,NULL));
    //frame rate
    TestTw(TwAddVarRO(m_bar, "FrameRate",TW_TYPE_FLOAT, &m_frameDisplay,
        "label='FrameRate: '"));
    TestTw(TwAddVarRO(m_bar, "FrameTime",TW_TYPE_DOUBLE, &m_FrameTimeDisplay,
        "label='Frame Time: '"));
    TestTw(TwAddSeparator(m_bar,NULL,NULL));
    //reset cam
    TwAddButton(m_bar,"Reset Camera", (TwButtonCallback)&Reset, NULL, NULL );
    TwAddButton(m_bar,"Reverse Camera", (TwButtonCallback)&Reverse, NULL, NULL );
    TestTw(TwAddSeparator(m_bar,NULL,NULL));
    TwAddButton(m_bar, "Average Task time (ms): ", NULL, NULL, NULL );
    for(int i = 0; i < 8; ++i)
    {
        std::string name = "Thread";
        std::stringstream nameSS;
        nameSS << i;
        name += nameSS.str();
        TestTw(TwAddVarRO(m_bar, name.c_str(), TW_TYPE_DOUBLE, m_scene.GetTimer(i), "Group = 'Threads'"));
    }
    TwDefine("Back/Threads opened=false");
    TestTw(TwAddSeparator(m_bar,NULL,NULL));
    TestTw(TwAddButton(m_bar, "Quit", (TwButtonCallback)&Quit, this, "help = 'Quits the Demo'"));
    //
    TestTw(TwAddSeparator(m_bar,NULL,NULL));
    TwAddButton(m_bar, "Left & Right: Zoom in / out", NULL, NULL, NULL );
    TwAddButton(m_bar, "S to toggle Depth buffer", NULL, NULL, NULL );
    TwAddButton(m_bar, "Esc to quit", NULL, NULL, NULL );
}
void MainRenderState::ResetCamera()
{
    m_scene.ResetCamera();
}
void MainRenderState::ChangeDirection()
{
    m_scene.m_cameraMove *= -1;
}